package com.woniu.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.DigestUtil;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.woniu.exception.LXLGException;
import com.woniu.user.common.UserException;
import com.woniu.user.common.util.JwtUtil;
import com.woniu.user.common.util.SendSMS;
import com.woniu.user.infra.model.UserAccount;
import com.woniu.user.infra.mapper.UserAccountMapper;
import com.woniu.user.infra.model.UserLoginLog;
import com.woniu.user.service.UserAccountService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.user.service.UserAttachmentService;
import com.woniu.user.service.UserLoginLogService;
import com.woniu.user.service.dto.UserInfoDto;
import com.woniu.user.service.param.RegisterServiceParam;
import com.woniu.user.service.param.UpdateUserInfoServiceParam;
import com.woniu.util.DateUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author Lucas
 * @since 2022-11-26
 */
@Service
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements UserAccountService {

    @Resource
    private StringRedisTemplate srt;
    @Resource
    private UserLoginLogService userLoginLogService;

    /**
     * 登录
     *
     * @param userPhone
     * @param password
     * @return
     */
    @Override
    public String login(String userPhone, String password) throws UnknownHostException {
        UserAccount user = getOne(new QueryWrapper<UserAccount>().eq("user_phone", userPhone));
        if (user == null) throw new LXLGException(UserException.ACCOUNT_ERROR);
        if (!user.getUserState().equals("NORMAL")) throw new LXLGException(UserException.ACCOUNT_STATE_EXCEPTION);
        if (!DigestUtil.bcryptCheck(password, user.getUserPassword()))
            throw new LXLGException(UserException.PASSWORD_ERROR);

        Map<String, Object> maps = new HashMap<String, Object>();
        maps.put("userId", user.getUserId());
        //认证token
        String token = JwtUtil.create(maps, 300);
        //记录登录日志
        UserLoginLog userLoginLog = new UserLoginLog();
        //获取本机ip
        InetAddress localHost = InetAddress.getLocalHost();
        String hostAddress = localHost.getHostAddress();

        userLoginLog.setLoginIp(hostAddress);
        userLoginLog.setLoginTime(DateUtil.parseDateLong());
        userLoginLog.setLoginType("SUCCESS");
        userLoginLog.setUserId(user.getUserId());
        userLoginLogService.save(userLoginLog);
        //返回token
        return token;
    }

    /**
     * 注册账号
     *
     * @param registerServiceParam
     * @return
     */
    @Override
    public boolean register(RegisterServiceParam registerServiceParam) {
        //检查手机号码是否存在
        UserAccount userPhone = getOne(new QueryWrapper<UserAccount>().eq("user_phone", registerServiceParam.getUserPhone()));
        if (userPhone != null) throw new LXLGException(UserException.PHONE_ISEXSIT);
        //判断验证码是否正确||是否存在
        String redisCode = srt.opsForValue().get("login:smsCode" + registerServiceParam.getUserPhone());
        if (redisCode == null || redisCode.equals(""))
            throw new LXLGException(UserException.SMSCODE_NO_ISEXSIT);
        if (!registerServiceParam.getSmsCode().equals(redisCode)) throw new LXLGException(UserException.SMSCODE_ERROR);
        //判断两次密码是否一致
        if (!DigestUtil.bcryptCheck(registerServiceParam.getRealPassword(), DigestUtil.bcrypt(registerServiceParam.getUserPassword())))
            throw new LXLGException(UserException.PASSWORD_OUT_OF_LINE);
        //存入账号表
        UserAccount userAccount = new UserAccount();
        userAccount.setUserNickname(registerServiceParam.getUserNickname());
        userAccount.setUserPassword(DigestUtil.bcrypt(registerServiceParam.getUserPassword()));
        userAccount.setUserPhone(registerServiceParam.getUserPhone());
        userAccount.setUserState("NORMAL");
        save(userAccount);
        return true;
    }
    /**
     * 发送验证码
     *
     * @param phone
     * @return
     */
    @Override
    public boolean sendCode(String phone) {
        //TODO 修改发送短信的手机号
        //查询验证码是否存在
        String code = srt.opsForValue().get("login:smsCode" + phone);
        if (code != null) throw new LXLGException(UserException.SMSCODE_ISEXSIT);
        //发送验证码
        String newCode = SendSMS.SendCode(phone);
        //存入redis
        srt.opsForValue().setIfAbsent("login:smsCode" + phone, newCode, 180, TimeUnit.SECONDS);
        return true;
    }

    /**
     * 完善信息
     * @param updateUserInfoServiceParam
     * @return
     */
    @Override
    public UserInfoDto updateInfo(UpdateUserInfoServiceParam updateUserInfoServiceParam) {
        // TODO 获取用户id
        Integer userId = 2;
        UserAccount userInfo = getOne(new QueryWrapper<UserAccount>().eq("user_id", userId));
        if (userInfo == null) throw new LXLGException(UserException.ACCOUNT_ERROR);
        //修改信息
        UserAccount userAccount = BeanUtil.copyProperties(updateUserInfoServiceParam, UserAccount.class);
        userAccount.setUserId(userId);
        updateById(userAccount);
        UserAccount userInfod = getOne(new QueryWrapper<UserAccount>().eq("user_id", userId));
        UserInfoDto userInfoDto = BeanUtil.copyProperties(userInfod, UserInfoDto.class);
        return userInfoDto;
    }

    /**
     * 查看用户个人信息
     * @return
     */
    @Override
    public UserInfoDto getUserInfo(Integer userId) {
        //TODO userId
        UserAccount userInfo = getOne(new QueryWrapper<UserAccount>().eq("user_id", userId));
        if (userInfo == null) throw new LXLGException(UserException.ACCOUNT_NOT_EXIST);
        UserInfoDto userInfoDto = BeanUtil.copyProperties(userInfo, UserInfoDto.class);
        return userInfoDto;
    }
}
